﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Возвращает, поддерживается ли установка обновлений конфигурации на данном компьютере.
// Установка обновления:
// - доступна только в ОС Windows;
// - не доступна при подключении через веб-сервер (т.к. обновление выполняется через пакетный запуск конфигуратора,
//   который выполняет прямое подключение к информационной базе);
// - возможна, если установлен конфигуратор (полный дистрибутив технологической платформы 1С:Предприятие для Windows);
// - доступна, если имеются права администрирования.
// - не доступна в модели сервиса (выполняется централизованно через Менеджер сервиса).
//
// Возвращаемое значение:
//    Структура:
//     * Поддерживается - Булево - Истина, если установка обновлений конфигурации поддерживается.
//     * ОписаниеОшибки - Строка - описание ошибки в случае, если не поддерживается.
//
Функция ПоддерживаетсяУстановкаОбновлений() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Поддерживается", Ложь);
	Результат.Вставить("ПоддерживаетсяУстановкаИсправлений", Ложь);
	Результат.Вставить("ОписаниеОшибки", "");
	
	Если ОбщегоНазначенияКлиент.РазделениеВключено() Тогда
		Результат.ОписаниеОшибки = 
			НСтр("ru = 'Установка обновлений для приложения в Интернете выполняется централизованно через Менеджер сервиса.'");
		Возврат Результат;
	КонецЕсли;
	
	Если Не ПользователиКлиент.ЭтоПолноправныйПользователь(Истина) Тогда
		Результат.ОписаниеОшибки = НСтр("ru = 'Для установки обновления требуются права администрирования.'");
		Возврат Результат;
	КонецЕсли;
	
#Если ВебКлиент Тогда
	
	Результат.ПоддерживаетсяУстановкаИсправлений = Истина;
	Результат.ОписаниеОшибки =
		НСтр("ru = 'В веб-клиенте доступна только установка исправлений.
			|Для установки обновления, установите
			|полный дистрибутив технологической платформы 1С:Предприятие для Windows.'");
	
#ИначеЕсли МобильныйКлиент Тогда
	Результат.ОписаниеОшибки = НСтр("ru = 'Установка обновления доступна только в ОС Windows.'");
#Иначе
	
	Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда 
		Результат.ОписаниеОшибки = НСтр("ru = 'Установка обновления доступна только в ОС Windows.'");
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиент.КлиентПодключенЧерезВебСервер() Тогда 
		Если Не ПустаяСтрока(Результат.ОписаниеОшибки) Тогда
			Результат.ОписаниеОшибки = Результат.ОписаниеОшибки + Символы.ПС + Символы.ПС; 
		КонецЕсли;
		
		Результат.ПоддерживаетсяУстановкаИсправлений = Истина;
		Результат.ОписаниеОшибки = Результат.ОписаниеОшибки
			+ НСтр("ru = 'При подключении через веб-сервер доступна только установка исправлений.
				|Для установки обновления, установите
				|полный дистрибутив технологической платформы 1С:Предприятие для Windows.'");
	КонецЕсли;
	
	Если Не ПоддерживаетсяПакетныйРежимКонфигуратора() Тогда 
		Если Не ПустаяСтрока(Результат.ОписаниеОшибки) Тогда
			Результат.ОписаниеОшибки = Результат.ОписаниеОшибки + Символы.ПС + Символы.ПС; 
		КонецЕсли;
		
		Результат.ОписаниеОшибки = Результат.ОписаниеОшибки
			+ НСтр("ru = 'Для установки обновления требуется конфигуратор.
				|Установите полный дистрибутив технологической платформы 1С:Предприятие для Windows.'");
	КонецЕсли;
	
#КонецЕсли
	
	Результат.Поддерживается = ПустаяСтрока(Результат.ОписаниеОшибки);
	
	Если Результат.Поддерживается Тогда 
		Результат.ПоддерживаетсяУстановкаИсправлений = Истина;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Открывает форму установки обновлений с указанными параметрами.
//
// Параметры:
//    ПараметрыУстановкиОбновлений - Структура - дополнительные параметры установки обновлений:
//     * ЗавершениеРаботыСистемы - Булево - Истина, если после установки обновления работа программы завершается. 
//                                          По умолчанию Ложь.
//     * ПолученоОбновлениеКонфигурации - Булево - Истина, если устанавливаемое обновление получено из приложения 
//                                          в Интернете. По умолчанию Ложь - обычный режим установки обновления.
//     * ВыполнитьОбновление     - Булево - Истина, если необходимо пропустить выбор файла обновления и сразу перейти
//                                          к установке обновления. По умолчанию Ложь - предлагать выбор.
//
Процедура ПоказатьПоискИУстановкуОбновлений(ПараметрыУстановкиОбновлений = Неопределено) Экспорт
	
	Результат = ПоддерживаетсяУстановкаОбновлений();
	Если Результат.Поддерживается
		Или Результат.ПоддерживаетсяУстановкаИсправлений Тогда
		
		ОткрытьФорму("Обработка.УстановкаОбновлений.Форма", ПараметрыУстановкиОбновлений);
	Иначе 
		ПоказатьПредупреждение(, Результат.ОписаниеОшибки);
	КонецЕсли;
	
КонецПроцедуры

// Отображает форму настроек создания резервной копии.
//
// Параметры:
//    ПараметрыРезервногоКопирования - Структура - параметры формы резервного копирования:
//      * СоздаватьРезервнуюКопию - Число - 0, Не создавать резервную копию ИБ;
//                                          1, Создавать временную резервную копию ИБ;
//                                          2, Создавать резервную копию ИБ.
//      * ИмяКаталогаРезервнойКопииИБ - Строка - каталог сохранения резервной копии.
//      * ВосстанавливатьИнформационнуюБазу - Булево - выполнять откат при нештатной ситуации.
//    ОписаниеОповещения - ОписаниеОповещения - описание оповещения о закрытии формы.
//
Процедура ПоказатьРезервноеКопирование(ПараметрыРезервногоКопирования, ОписаниеОповещения) Экспорт
	
	ОткрытьФорму("Обработка.УстановкаОбновлений.Форма.НастройкаРезервнойКопии", ПараметрыРезервногоКопирования,,,,, ОписаниеОповещения);
	
КонецПроцедуры

#Область ДляВызоваИзДругихПодсистем

// ИнтернетПоддержкаПользователей.ПолучениеОбновленийПрограммы

// Возвращает текст заголовка настроек резервного копирования для отображения на форме.
//
// Параметры:
//    Параметры - Структура - параметры резервного копирования.
//
// Возвращаемое значение:
//    Строка - заголовок гиперссылки создания резервной копии.
//
Функция ЗаголовокСозданияРезервнойКопии(Параметры) Экспорт
	
	Если Параметры.СоздаватьРезервнуюКопию = 0 Тогда
		Возврат НСтр("ru = 'Не создавать резервную копию ИБ'");
	ИначеЕсли Параметры.СоздаватьРезервнуюКопию = 1 Тогда
		Если Параметры.ВосстанавливатьИнформационнуюБазу Тогда 
			Возврат НСтр("ru = 'Создавать временную резервную копию ИБ и выполнять откат при нештатной ситуации'");
		Иначе 
			Возврат НСтр("ru = 'Создавать временную резервную копию ИБ и не выполнять откат при нештатной ситуации'");
		КонецЕсли;
	ИначеЕсли Параметры.СоздаватьРезервнуюКопию = 2 Тогда
		Если Параметры.ВосстанавливатьИнформационнуюБазу Тогда 
			Возврат НСтр("ru = 'Создавать резервную копию ИБ и выполнять откат при нештатной ситуации'");
		Иначе 
			Возврат НСтр("ru = 'Создавать резервную копию ИБ и не выполнять откат при нештатной ситуации'");
		КонецЕсли;
	Иначе
		Возврат "";
	КонецЕсли;
	
КонецФункции

// Проверяет возможность установки обновления. Если возможно, то запускает
// скрипт обновления или планирует обновление на указанное время.
//
// Параметры:
//    Форма - ФормаКлиентскогоПриложения - форма, из которой устанавливается обновление и которая должна быть закрыта в конце. 
//    Параметры - Структура - параметры установки обновления:
//        * РежимОбновления - Число - вариант установки обновления. Принимаемые значения:
//                                    0 - сейчас, 1 - при завершении работы, 2 - планирование обновления.
//        * ДатаВремяОбновления - Дата - дата планируемого обновления.
//        * ВыслатьОтчетНаПочту - Булево - признак необходимости отправки отчета на почту.
//        * АдресЭлектроннойПочты - Строка - адрес электронной почты для отправки отчета о результате обновления.
//        * КодЗадачиПланировщика - Число - код задачи запланированного обновления.
//        * ИмяФайлаОбновления - Строка - имя файла устанавливаемого обновления.
//        * СоздаватьРезервнуюКопию - Число - признак необходимости создания резервной копии.
//        * ИмяКаталогаРезервнойКопииИБ - Строка - каталог сохранения резервной копии.
//        * ВосстанавливатьИнформационнуюБазу - Булево - признак необходимости восстановления базы.
//        * ЗавершениеРаботыСистемы - Булево - признак того, что установка обновления происходит при завершении работы.
//        * ФайлыОбновления - Массив из Структура:
//           ** ПолноеИмяФайлаОбновления - Строка
//           ** ВыполнитьОбработчикиОбновления - Булево - выполнить после перехода на эту версию.
//        * Исправления - Структура:
//           ** Установить - Массив - пути к файлам исправлений во временном хранилище,
//                                    которые требуется установить.
//           ** Удалить    - Массив - уникальные идентификаторы (Строка) исправлений, которые требуется удалить.
//        * КаталогПлатформы - Строка - путь к платформе, на которой должно быть запущено обновление, если не указано
//                                    запускается на платформе текущего сеанса.
//    ПараметрыАдминистрирования - см. СтандартныеПодсистемыСервер.ПараметрыАдминистрирования.
//
Процедура УстановитьОбновление(Форма, Параметры, ПараметрыАдминистрирования) Экспорт
	
#Если Не ВебКлиент И Не МобильныйКлиент Тогда
	
	Если Не ВозможнаУстановкаОбновления(Параметры, ПараметрыАдминистрирования) Тогда
		Возврат;
	КонецЕсли;
	
	ОбновлениеКонфигурацииВызовСервера.СохранитьНастройкиОбновленияКонфигурации(Параметры);
	
	Если Форма <> Неопределено Тогда
		Если Параметры.РежимОбновления = 0 Тогда
			ИмяПараметра = "СтандартныеПодсистемы.ПропуститьЗавершениеРаботыСистемыПослеОбработкиПредупреждений";
			ПараметрыПриложения.Вставить(ИмяПараметра, Истина);
			Попытка
				Форма.Закрыть();
			Исключение
				ПараметрыПриложения.Удалить(ИмяПараметра);
				ВызватьИсключение;
			КонецПопытки;
			ПараметрыПриложения.Удалить(ИмяПараметра);
		Иначе
			Форма.Закрыть();
		КонецЕсли;
	КонецЕсли;
	
	Если Параметры.РежимОбновления = 0 Тогда // Обновить сейчас
		ЗапуститьСкриптОбновления(Параметры, ПараметрыАдминистрирования);
	ИначеЕсли Параметры.РежимОбновления = 1 Тогда // При завершении работы
		ИмяПараметра = "СтандартныеПодсистемы.ПредлагатьОбновлениеИнформационнойБазыПриЗавершенииСеанса";
		ПараметрыПриложения.Вставить(ИмяПараметра, Истина);
		ПараметрыПриложения.Вставить("СтандартныеПодсистемы.ИменаФайловОбновления", ИменаФайловОбновления(Параметры, Неопределено));
	ИначеЕсли Параметры.РежимОбновления = 2 Тогда // Запланировать обновление
		ЗапланироватьОбновлениеКонфигурации(Параметры, ПараметрыАдминистрирования);
	КонецЕсли;
	
#КонецЕсли
	
КонецПроцедуры

// Конец ИнтернетПоддержкаПользователей.ПолучениеОбновленийПрограммы

#КонецОбласти

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

Процедура ОбработатьРезультатОбновления(РезультатОбновления, КаталогСкрипта) Экспорт
	
	Если ПустаяСтрока(КаталогСкрипта) Тогда
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			"Предупреждение", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Журнал обновления см. в папке временных файлов %1.(цифры).'"), "%temp%\1Cv8Update"),, Истина);
		РезультатОбновления = Истина; // считаем обновление успешным.
	Иначе 
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			"Информация", 
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Папка с журналом обновления: %1'"), КаталогСкрипта),, Истина);
		
#Если Не ВебКлиент И Не МобильныйКлиент Тогда
		ПрочитатьДанныеВЖурналРегистрации(РезультатОбновления, КаталогСкрипта);
#КонецЕсли
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаписатьОшибкуНеобходимостиОбновленияПлатформы(ТекстОшибки) Экспорт
	
	КаталогСкрипта = ОбновлениеКонфигурацииВызовСервера.КаталогСкрипта();
	ЗаписатьФайлПротоколаОшибкиИЗавершитьРаботу(КаталогСкрипта, ТекстОшибки);
	
КонецПроцедуры

// Обновляет конфигурацию базы данных.
//
// Параметры:
//  СтандартнаяОбработка - Булево - если в процедуре установить данному параметру значение Ложь, то инструкция по
//                                  "ручному" обновлению показана не будет.
//
Процедура УстановитьОбновлениеКонфигурации(ЗавершениеРаботыСистемы = Ложь) Экспорт
	
	ПараметрыФормы = Новый Структура("ЗавершениеРаботыСистемы, ПолученоОбновлениеКонфигурации",
		ЗавершениеРаботыСистемы, ЗавершениеРаботыСистемы);
	ПоказатьПоискИУстановкуОбновлений(ПараметрыФормы);
	
КонецПроцедуры

// Записывает в каталог скрипта файл-маркер ошибки.
//
Процедура ЗаписатьФайлПротоколаОшибкиИЗавершитьРаботу(Знач ИмяКаталога, Знач ПодробноеПредставлениеОшибки) Экспорт
	
#Если Не ВебКлиент Тогда
	
	Если СтрНайти(ПараметрЗапуска, "ВыполнитьОбновлениеИЗавершитьРаботу") > 0 Тогда
		
		Каталог = Новый Файл(ИмяКаталога);
		Если Каталог.Существует() И Каталог.ЭтоКаталог() Тогда // АПК:566 синхронные вызовы не в веб-клиенте допустимы.
			
			ФайлРегистрации = Новый ЗаписьТекста(ИмяКаталога + "error.txt");
			ФайлРегистрации.Закрыть();
			
			ФайлЛога = Новый ЗаписьТекста(ИмяКаталога + "templog.txt", КодировкаТекста.Системная);
			ФайлЛога.Записать(ПодробноеПредставлениеОшибки);
			ФайлЛога.Закрыть();
			
			ПрекратитьРаботуСистемы();
			
		КонецЕсли;
	КонецЕсли;
	
#КонецЕсли
	
КонецПроцедуры

// Открывает форму со списком установленных исправлений.
//
Процедура ПоказатьУстановленныеИсправления(Параметры = Неопределено, РежимОткрытия = Неопределено) Экспорт
	
	Если Параметры = Неопределено Тогда
		Параметры = Новый Структура;
	КонецЕсли;
	
	ОткрытьФорму("ОбщаяФорма.УстановленныеИсправления", Параметры,,,,,, РежимОткрытия);
	
КонецПроцедуры

// Определяет, является ли расширение с переданным именем исправлением (патчем).
// Параметры:
//  ИмяИсправления - Строка - имя проверяемого расширения.
//
Функция ЭтоИсправление(ИмяИсправления) Экспорт
	Возврат СтрНачинаетсяС(ИмяИсправления, "EF_");
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ОбщегоНазначенияКлиентПереопределяемый.ПриНачалеРаботыСистемы.
Процедура ПриНачалеРаботыСистемы(Параметры) Экспорт
	
	ПроверитьОбновлениеКонфигурации();
	
КонецПроцедуры

// Параметры:
//  Отказ - см. ОбщегоНазначенияКлиентПереопределяемый.ПередЗавершениемРаботыСистемы.Отказ
//  Предупреждения - см. ОбщегоНазначенияКлиентПереопределяемый.ПередЗавершениемРаботыСистемы.Предупреждения
//
Процедура ПередЗавершениемРаботыСистемы(Отказ, Предупреждения) Экспорт
	
	// Предупреждение: при выставлении своего флажка подсистема "Обновление конфигурации" очищает список
	// всех ранее добавленных предупреждений.
	Если ПараметрыПриложения["СтандартныеПодсистемы.ПредлагатьОбновлениеИнформационнойБазыПриЗавершенииСеанса"] = Истина Тогда
		ПараметрыПредупреждения = СтандартныеПодсистемыКлиент.ПредупреждениеПриЗавершенииРаботы();
		ПараметрыПредупреждения.ТекстФлажка  = НСтр("ru = 'Установить обновление конфигурации'");
		ПараметрыПредупреждения.ТекстПредупреждения  = НСтр("ru = 'Запланирована установка обновления'");
		ПараметрыПредупреждения.Приоритет = 50;
		ПараметрыПредупреждения.ВывестиОдноПредупреждение = Истина;
		
		ДействиеПриУстановленномФлажке = ПараметрыПредупреждения.ДействиеПриУстановленномФлажке;
		ДействиеПриУстановленномФлажке.Форма = "Обработка.УстановкаОбновлений.Форма";
		ДействиеПриУстановленномФлажке.ПараметрыФормы = Новый Структура("ЗавершениеРаботыСистемы, ВыполнитьОбновление", 
			Истина, Истина);
		
		Предупреждения.Добавить(ПараметрыПредупреждения);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция ВозможнаУстановкаОбновления(Параметры, ПараметрыАдминистрирования)
	
	Результат = ПоддерживаетсяУстановкаОбновлений();
	Если Не Результат.Поддерживается Тогда 
		ПоказатьПредупреждение(, Результат.ОписаниеОшибки);
		Возврат Ложь;
	КонецЕсли;
	
	ЭтоФайловаяБаза = ОбщегоНазначенияКлиент.ИнформационнаяБазаФайловая();
	
	Если ЭтоФайловаяБаза И Параметры.СоздаватьРезервнуюКопию = 2 Тогда
		Файл = Новый Файл(Параметры.ИмяКаталогаРезервнойКопииИБ);
		Если Не Файл.Существует() Или Не Файл.ЭтоКаталог() Тогда // АПК:566 синхронные вызовы вне веб-клиента разрешены;
			ПоказатьПредупреждение(,
				НСтр("ru = 'Укажите существующую папку для сохранения резервной копии ИБ.'"));
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если Параметры.РежимОбновления = 0 Тогда // Обновить сейчас
		ИмяПараметра = "СтандартныеПодсистемы.СообщенияДляЖурналаРегистрации";
		Если ЭтоФайловаяБаза
			И ОбновлениеКонфигурацииВызовСервера.НаличиеАктивныхСоединений(ПараметрыПриложения[ИмяПараметра]) Тогда
			
			ПоказатьПредупреждение(,
				НСтр("ru = 'Невозможно продолжить обновление конфигурации,
				           |так как не завершены все соединения с информационной базой.'"));
			Возврат Ложь;
		КонецЕсли;
	ИначеЕсли Параметры.РежимОбновления = 2 Тогда
		Если Не ДатаОбновленияУказанаВерно(Параметры) Тогда
			Возврат Ложь;
		КонецЕсли;
		
		УказанНеДопустимыйАдресЭлектроннойПочты = Параметры.ВыслатьОтчетНаПочту
			И Не ОбщегоНазначенияКлиентСервер.АдресЭлектроннойПочтыСоответствуетТребованиям(Параметры.АдресЭлектроннойПочты);
		
		Если УказанНеДопустимыйАдресЭлектроннойПочты Тогда
			ПоказатьПредупреждение(,
				НСтр("ru = 'Укажите допустимый адрес электронной почты.'"));
			Возврат Ложь;
		КонецЕсли;
		
		Если Не ПоддерживаетсяПланировщикЗаданий() Тогда
			ПоказатьПредупреждение(,
				НСтр("ru = 'Планировщик заданий поддерживается только начиная с операционной системы версии 6.0 Vista.'"));
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Функция ДатаОбновленияУказанаВерно(Параметры)
	
	ТекущаяДата = ОбщегоНазначенияКлиент.ДатаСеанса();
	Если Параметры.ДатаВремяОбновления < ТекущаяДата Тогда
		ТекстСообщения = НСтр("ru = 'Обновление конфигурации может быть запланировано только на будущую дату и время.'");
	ИначеЕсли Параметры.ДатаВремяОбновления > ДобавитьМесяц(ТекущаяДата, 1) Тогда
		ТекстСообщения = НСтр("ru = 'Обновление конфигурации может быть запланировано не позднее, чем через месяц относительно текущей даты.'");
	КонецЕсли;
	
	ДатаУказанаВерно = ПустаяСтрока(ТекстСообщения);
	Если Не ДатаУказанаВерно Тогда
		ПоказатьПредупреждение(, ТекстСообщения);
	КонецЕсли;
	
	Возврат ДатаУказанаВерно;
	
КонецФункции

Процедура ВставитьПараметрСкрипта(Знач ИмяПараметра, Знач ЗначениеПараметра, Форматировать, ОбластьПараметров)
	
	Если Форматировать Тогда
		ЗначениеПараметра = Форматировать(ЗначениеПараметра);
	ИначеЕсли ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда
		ЗначениеПараметра = ?(ЗначениеПараметра, "true", "false");
	КонецЕсли;
	ОбластьПараметров = СтрЗаменить(ОбластьПараметров, "[" + ИмяПараметра + "]", ЗначениеПараметра);
	
КонецПроцедуры

Функция ИменаФайловОбновления(Параметры, ТолькоПервыйФайл = Ложь)
	
	ИмяПараметра = "СтандартныеПодсистемы.ИменаФайловОбновления";
	Если ПараметрыПриложения.Получить(ИмяПараметра) <> Неопределено Тогда
		Если ТолькоПервыйФайл = Истина Тогда
			Возврат ПараметрыПриложения[ИмяПараметра].ИмяПервогоФайла;
		ИначеЕсли ТолькоПервыйФайл = Ложь Тогда
			Возврат ПараметрыПриложения[ИмяПараметра].ИменаФайлов;
		КонецЕсли;
		Возврат ПараметрыПриложения[ИмяПараметра];
	КонецЕсли;
	
	Если Параметры.Свойство("НуженФайлОбновления") И Не Параметры.НуженФайлОбновления Тогда
		ИмяПервогоФайла = "";
		ИменаФайловОбновления = "";
	Иначе
		ИмяПервогоФайла = Null;
		Если ПустаяСтрока(Параметры.ИмяФайлаОбновления) Тогда
			ИменаФайлов = Новый Массив;
			Для Каждого ФайлОбновления Из Параметры.ФайлыОбновления Цикл
				Если ИмяПервогоФайла = Null Тогда
					ИмяПервогоФайла = ФайлОбновления.ПолноеИмяФайлаОбновления;
				КонецЕсли;
				ПрефиксФайлаОбновления = ?(ФайлОбновления.ВыполнитьОбработчикиОбновления, "+", "");
				ИменаФайлов.Добавить(Форматировать(ПрефиксФайлаОбновления + ФайлОбновления.ПолноеИмяФайлаОбновления));
			КонецЦикла;
			ИменаФайловОбновления = СтрСоединить(ИменаФайлов, ",");
		Иначе
			ИменаФайловОбновления = Форматировать(Параметры.ИмяФайлаОбновления);
			ИмяПервогоФайла = Параметры.ИмяФайлаОбновления;
		КонецЕсли;
	КонецЕсли;
	
	ИмяПервогоФайла = ?(ИмяПервогоФайла = Null, "", ИмяПервогоФайла);
	ИменаФайловОбновления = "[" + ИменаФайловОбновления + "]";
	
	Если ТолькоПервыйФайл = Истина Тогда
		Возврат ИмяПервогоФайла;
	ИначеЕсли ТолькоПервыйФайл = Ложь Тогда
		Возврат ИменаФайловОбновления;
	КонецЕсли;
	
	Возврат Новый Структура("ИмяПервогоФайла, ИменаФайлов",
		ИмяПервогоФайла, ИменаФайловОбновления);
	
КонецФункции

Функция Форматировать(Знач Текст)
	Текст = СтрЗаменить(Текст, "\", "\\");
	Текст = СтрЗаменить(Текст, """", "\""");
	Текст = СтрЗаменить(Текст, "'", "\'");
	Возврат "'" + Текст + "'";
КонецФункции

Функция КодировкаЛогФайла(Знач КаталогПрограммы)
	
	КодировкаЛогФайла = "UTF-8";
	ЧастиКаталогаПрограммы = СтрРазделить(КаталогПрограммы, ПолучитьРазделительПути(), Ложь);
	Для каждого НомерВерсииПрограммы Из ЧастиКаталогаПрограммы Цикл
		ЧастиНомераВерсииПрограммы = СтрРазделить(НомерВерсииПрограммы, ".", Ложь);
		Если ЧастиНомераВерсииПрограммы.Количество() <> 4 Тогда
			Продолжить;	
		КонецЕсли;
		ЭтоНомерВерсии = Истина;
		Для каждого ЧастьНомераВерсииПрограммы Из ЧастиНомераВерсииПрограммы Цикл
			Если Не ЭтоЧисло(ЧастьНомераВерсииПрограммы) Тогда
				ЭтоНомерВерсии = Ложь;
				Прервать;	
			КонецЕсли;
		КонецЦикла;
		Если Не ЭтоНомерВерсии Тогда
			Продолжить;	
		КонецЕсли;
	КонецЦикла;
	Возврат КодировкаЛогФайла;

КонецФункции

Функция ЭтоЧисло(Знач ПроверяемоеЗначение)
	
	Если ПроверяемоеЗначение = "0" Тогда
		Возврат Истина;
	КонецЕсли;
	
	ОписаниеЧисла = Новый ОписаниеТипов("Число");
	Возврат ОписаниеЧисла.ПривестиЗначение(ПроверяемоеЗначение) <> 0;
	
КонецФункции

Функция ПолучитьПараметрыАутентификацииАдминистратораОбновления(ПараметрыАдминистрирования)
	
	Результат = Новый Структура("СтрокаПодключения, СтрокаСоединенияИнформационнойБазы");
	
	ПортКластера = ПараметрыАдминистрирования.ПортКластера;
	ТекущиеСоединения = СоединенияИБВызовСервера.ИнформацияОСоединениях(Истина,
		ПараметрыПриложения["СтандартныеПодсистемы.СообщенияДляЖурналаРегистрации"], ПортКластера);
	
	СтрокаСоединения = ТекущиеСоединения.СтрокаСоединенияИнформационнойБазы;
	ПутьКБазе = "";
	Если СтрНайти(СтрокаСоединения, "'") > 0 Тогда
		БазаФайловая = ОбщегоНазначенияКлиент.ИнформационнаяБазаФайловая(СтрокаСоединения);
		Если БазаФайловая Тогда
			ПутьКБазе = СтрЗаменить(СтрЗаменить(СтрокаСоединения, "File=", ""), ";", "");
			ТекстОшибки = НСтр("ru = 'Невозможно выполнить обновление на новую версию приложения, т.к. каталог
				|информационной базы содержит недопустимый символ одинарной кавычки "" '' "":
				|%1%2'");
			ПостФикс = НСтр("ru = 'Переместите информационную базу в другой каталог и повторите попытку обновления.'");
		Иначе
			ПутьКБазе = СтрокаСоединения;
			ТекстОшибки = НСтр("ru = 'Невозможно выполнить обновление на новую версию приложения, т.к. в адресе
				|сервера или имени информационной базы содержится недопустимый символ одинарной кавычки "" '' "":
				|%1%2'");
			ПостФикс = НСтр("ru = 'Переместите информационную базу на другой сервер или переименуйте ее, затем повторите попытку обновления.'");
		КонецЕсли;
		ТекстОшибки = СтрСоединить(СтрРазделить(ТекстОшибки, Символы.ПС), " ");
		
		ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ПостФикс;
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, Символы.ПС, ПутьКБазе);
		
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Результат.СтрокаСоединенияИнформационнойБазы = ТекущиеСоединения.СтрокаСоединенияИнформационнойБазы;
	Результат.СтрокаПодключения = "Usr=""{0}"";Pwd=""{1}""";
	
	Возврат Результат;
	
КонецФункции

Функция ИмяЗадачиScheduleService(Знач КодЗадачи)
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Обновление конфигурации (%1)'"), Формат(КодЗадачи, "ЧГ=0"));
	
КонецФункции

Функция СтрокаUnicode(Строка)
	
	Результат = "";
	
	Для НомерСимвола = 1 По СтрДлина(Строка) Цикл
		
		Символ = Формат(КодСимвола(Сред(Строка, НомерСимвола, 1)), "ЧГ=0");
		Символ = СтроковыеФункцииКлиентСервер.ДополнитьСтроку(Символ, 4);
		Результат = Результат + Символ;
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Возвращает имя события для записи журнала регистрации.
Функция СобытиеЖурналаРегистрации() Экспорт
	Возврат НСтр("ru = 'Обновление конфигурации'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка());
КонецФункции

// Проверяет наличие обновления конфигурации при запуске программы.
//
Процедура ПроверитьОбновлениеКонфигурации()
	
	Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
		Возврат;
	КонецЕсли;
	
#Если Не ВебКлиент И Не МобильныйКлиент Тогда
	Если ОбщегоНазначенияКлиент.РазделениеВключено()
	 Или Не ОбщегоНазначенияКлиент.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	ПараметрыРаботыКлиента = СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиентаПриЗапуске();
	Если ПараметрыРаботыКлиента.Свойство("ПоказатьСообщениеОбОшибочныхОбработчиках") Тогда
		Возврат; // Форма результатов обновления будет показана позже.
	КонецЕсли;
	
	НастройкиОбновления = ПараметрыРаботыКлиента.НастройкиОбновления;
	НаличиеОбновления = НастройкиОбновления.ПроверитьПрошлыеОбновленияБазы;
	
	Если НаличиеОбновления Тогда
		// Надо завершить предыдущее обновление.
		ОткрытьФорму("Обработка.РезультатыОбновленияПрограммы.Форма.РезультатыОбновленияПрограммы");
		Возврат;
	КонецЕсли;
	
	Если НастройкиОбновления.КонфигурацияИзменена Тогда
		ПоказатьОповещениеПользователя(НСтр("ru = 'Обновление конфигурации'"),
			"e1cib/app/Обработка.УстановкаОбновлений",
			НСтр("ru = 'Конфигурация отличается от основной конфигурации информационной базы.'"), 
			БиблиотекаКартинок.Информация32);
	КонецЕсли;
	
#КонецЕсли

КонецПроцедуры

Функция ПоддерживаетсяПланировщикЗаданий()
	
	// Планировщик заданий поддерживается начиная с версии 6.0 - Windows Vista.
	
	СистемнаяИнформация = Новый СистемнаяИнформация();
	
	ПозицияТочки = СтрНайти(СистемнаяИнформация.ВерсияОС, ".");
	Если ПозицияТочки < 2 Тогда 
		Возврат Ложь;
	КонецЕсли;
	
	НомерВерсии = Сред(СистемнаяИнформация.ВерсияОС, ПозицияТочки - 2, 2);
	
	ОписаниеТипаЧисло = Новый ОписаниеТипов("Число");
	ВерсияВышеVista = ОписаниеТипаЧисло.ПривестиЗначение(НомерВерсии) >= 6;
	
	Возврат ВерсияВышеVista;
	
КонецФункции

Процедура ЗаписатьСобытияВЖурналРегистрации() Экспорт
	
	СобытияДляЖурналаРегистрации = ПараметрыПриложения["СтандартныеПодсистемы.СообщенияДляЖурналаРегистрации"];
	
	Если ТипЗнч(СобытияДляЖурналаРегистрации) <> Тип("СписокЗначений") Тогда
		Возврат;
	КонецЕсли;
	
	Если СобытияДляЖурналаРегистрации.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ЖурналРегистрацииВызовСервера.ЗаписатьСобытияВЖурналРегистрации(СобытияДляЖурналаРегистрации);
	
КонецПроцедуры

#Если Не ВебКлиент И Не МобильныйКлиент Тогда

Процедура ПрочитатьДанныеВЖурналРегистрации(РезультатОбновления, КаталогСкрипта)
	
	РезультатОбновления = Неопределено;
	ПриОбновленииПроизошлаОшибка = Ложь;
	
	МассивФайлов = НайтиФайлы(КаталогСкрипта, "log*.txt");
	
	Если МассивФайлов.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ФайлЖурнала = МассивФайлов[0];
	
	ТекстовыйДокумент = Новый ТекстовыйДокумент;
	ТекстовыйДокумент.Прочитать(ФайлЖурнала.ПолноеИмя);
	
	Для НомерСтроки = 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл
		
		ТекущаяСтрока = ТекстовыйДокумент.ПолучитьСтроку(НомерСтроки);
		Если ПустаяСтрока(ТекущаяСтрока) Тогда
			Продолжить;
		КонецЕсли;
		
		ПредставлениеУровня = "Информация";
		Если Сред(ТекущаяСтрока, 3, 1) = "." И Сред(ТекущаяСтрока, 6, 1) = "." Тогда // Строка с датой
			МассивСтроки = СтрРазделить(ТекущаяСтрока, " ", Ложь);
			МассивДаты = СтрРазделить(МассивСтроки[0], ".");
			МассивВремени = СтрРазделить(МассивСтроки[1], ":");
			ДатаСобытия = Дата(МассивДаты[2], МассивДаты[1], МассивДаты[0], МассивВремени[0], МассивВремени[1], МассивВремени[2]);
			Если МассивСтроки[2] = "{ERR}" Тогда
				ПредставлениеУровня = "Ошибка";
				ПриОбновленииПроизошлаОшибка = Истина;
			КонецЕсли;
			
			Комментарий = СокрЛП(Сред(ТекущаяСтрока, СтрНайти(ТекущаяСтрока, "}") + 2));
			Если СтрНачинаетсяС(Комментарий, "ОбновлениеВыполненоУспешно") 
				Или Комментарий = "Обновление выполнено" Тогда // АПК:1297 не локализуется (фрагмент журнала), для совместимости
				РезультатОбновления = Истина;
				Продолжить;
			ИначеЕсли СтрНачинаетсяС(Комментарий, "ОбновлениеНеВыполнено")  
				Или Комментарий = "Обновление не выполнено" Тогда // АПК:1297 не локализуется (фрагмент журнала), для совместимости
				РезультатОбновления = Ложь;
				Продолжить;
			КонецЕсли;
			
			Для НомерСледСтроки = НомерСтроки + 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл
				ТекущаяСтрока = ТекстовыйДокумент.ПолучитьСтроку(НомерСледСтроки);
				Если Сред(ТекущаяСтрока, 3, 1) = "." И Сред(ТекущаяСтрока, 6, 1) = "." Тогда
					// Следующая строка - строка нового события.
					НомерСтроки = НомерСледСтроки - 1;
					Прервать;
				КонецЕсли;
				
				Комментарий = Комментарий + Символы.ПС + ТекущаяСтрока;
			КонецЦикла;
			
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(), 
				ПредставлениеУровня, Комментарий, ДатаСобытия);
			
		КонецЕсли;
		
	КонецЦикла;
	
	// Если обновление выполнялось с версии БСП ниже 2.3.1.6, то записей лога
	// - "Обновление выполнено"
	// - "Обновление не выполнено"
	// может не быть, потому будем опираться на то - происходили ли ошибки в ходе обновления.
	Если РезультатОбновления = Неопределено Тогда 
		РезультатОбновления = Не ПриОбновленииПроизошлаОшибка;
	КонецЕсли;
	
	ЗаписатьСобытияВЖурналРегистрации();

КонецПроцедуры

Функция КодировкаФайловПрограммыОбновления()
	
	// wscript.exe может работать только с файлами в кодировке UTF-16 LE.
	Возврат КодировкаТекста.UTF16;
	
КонецФункции

Функция ИменаФайловИсправлений(Параметры, КаталогВременныхФайлов)
	
	ИмяПараметра = "СтандартныеПодсистемы.ИменаФайловИсправлений";
	Если ПараметрыПриложения.Получить(ИмяПараметра) <> Неопределено Тогда
		Возврат ПараметрыПриложения[ИмяПараметра];
	КонецЕсли;
	
	ИменаФайлов = Новый Массив;
	Для Каждого ИмяФайлаИсправления Из Параметры.ФайлыИсправлений Цикл
		Если СтрЗаканчиваетсяНа(ИмяФайлаИсправления, ".cfe") Тогда
			ИмяАрхива = КаталогВременныхФайлов + СтрЗаменить(Строка(Новый УникальныйИдентификатор),"-", "") + ".zip";
			ЗаписьАрхива = Новый ЗаписьZipФайла(ИмяАрхива);
			ЗаписьАрхива.Добавить(ИмяФайлаИсправления);
			ЗаписьАрхива.Записать();
			
			ИменаФайлов.Добавить(Форматировать(ИмяАрхива));
		Иначе
			ИменаФайлов.Добавить(Форматировать(ИмяФайлаИсправления));
		КонецЕсли;
	КонецЦикла;
	ИменаФайловИсправлений = СтрСоединить(ИменаФайлов, ",");
	
	Возврат "[" + ИменаФайловИсправлений + "]";
	
КонецФункции

Функция ИнформацияОбИсправлениях(Параметры, КаталогВременныхФайлов)
	
	ИмяПараметра = "СтандартныеПодсистемы.ИнформацияОбИсправлениях";
	Если ПараметрыПриложения.Получить(ИмяПараметра) <> Неопределено Тогда
		Возврат ПараметрыПриложения[ИмяПараметра];
	КонецЕсли;
	
	УстанавливаемыеИсправления = "['']";
	УдаляемыеИсправления = "['']";
	Если Параметры.Свойство("ФайлыИсправлений") Тогда
		УстанавливаемыеИсправления = ИменаФайловИсправлений(Параметры, КаталогВременныхФайлов);
	ИначеЕсли Параметры.Свойство("Исправления") Тогда
		Если Параметры.Исправления.Свойство("Установить")
			И Параметры.Исправления.Установить.Количество() > 0 Тогда
			ИменаФайлов = Новый Массив;
			Для Каждого НовоеИсправление Из Параметры.Исправления.Установить Цикл
				ИмяАрхива = КаталогВременныхФайлов + СтрЗаменить(Строка(Новый УникальныйИдентификатор),"-", "") + ".zip";
				Данные = ПолучитьИзВременногоХранилища(НовоеИсправление); // ДвоичныеДанные
				Данные.Записать(ИмяАрхива);
				ИменаФайлов.Добавить(Форматировать(ИмяАрхива));
			КонецЦикла;
			УстанавливаемыеИсправления = СтрСоединить(ИменаФайлов, ",");
			УстанавливаемыеИсправления = "[" + УстанавливаемыеИсправления + "]";
		КонецЕсли;
		
		Если Параметры.Исправления.Свойство("Удалить")
			И Параметры.Исправления.Удалить.Количество() > 0 Тогда
			УдаляемыеИсправления = "'" + СтрСоединить(Параметры.Исправления.Удалить, "','") + "'";
			УдаляемыеИсправления = "[" + УдаляемыеИсправления + "]";
		КонецЕсли;
	КонецЕсли;
	
	ИнформацияОбИсправлениях = Новый Структура;
	ИнформацияОбИсправлениях.Вставить("Установить", УстанавливаемыеИсправления);
	ИнформацияОбИсправлениях.Вставить("Удалить", УдаляемыеИсправления);
	
	Возврат ИнформацияОбИсправлениях;
	
КонецФункции

Функция СформироватьФайлыСкриптаОбновления(Знач ИнтерактивныйРежим, Параметры, ПараметрыАдминистрирования)
	
	ЭтоФайловаяБаза = ОбщегоНазначенияКлиент.ИнформационнаяБазаФайловая();
	
	КаталогПлатформы = Неопределено;
	Параметры.Свойство("КаталогПлатформы", КаталогПлатформы);
	КаталогПрограммы = ?(ЗначениеЗаполнено(КаталогПлатформы), КаталогПлатформы, КаталогПрограммы());
	
	ИмяИсполняемогоФайлаКонфигуратора = КаталогПрограммы + СтандартныеПодсистемыКлиент.ИмяИсполняемогоФайлаПриложения(Истина);
	ИмяИсполняемогоФайлаКлиента = КаталогПрограммы + СтандартныеПодсистемыКлиент.ИмяИсполняемогоФайлаПриложения();
	ПутьКCOMСоединителю = КаталогПрограммы() + "comcntr.dll";
	ИмяCOMСоединителя = ОбщегоНазначенияКлиентСервер.ИмяCOMСоединителя();
	КодировкаЛогФайла = КодировкаЛогФайла(КаталогПрограммы);
	ИспользоватьCOMСоединитель = Не (СтандартныеПодсистемыКлиент.ЭтоБазоваяВерсияКонфигурации()
		Или СтандартныеПодсистемыКлиент.ЭтоУчебнаяПлатформа());
	
	ПараметрыСкрипта = ПолучитьПараметрыАутентификацииАдминистратораОбновления(ПараметрыАдминистрирования);
	СтрокаСоединенияИнформационнойБазы = ПараметрыСкрипта.СтрокаСоединенияИнформационнойБазы + ПараметрыСкрипта.СтрокаПодключения;
	Если СтрЗаканчиваетсяНа(СтрокаСоединенияИнформационнойБазы, ";") Тогда
		СтрокаСоединенияИнформационнойБазы = Лев(СтрокаСоединенияИнформационнойБазы, СтрДлина(СтрокаСоединенияИнформационнойБазы) - 1);
	КонецЕсли;
	
	// Определение пути к информационной базе.
	ПутьКИнформационнойБазе = СоединенияИБКлиентСервер.ПутьКИнформационнойБазе(, ПараметрыАдминистрирования.ПортКластера);
	ПараметрПутиКИнформационнойБазе = ?(ЭтоФайловаяБаза, "/F", "/S") + ПутьКИнформационнойБазе;
	СтрокаПутиКИнформационнойБазе = ?(ЭтоФайловаяБаза, ПутьКИнформационнойБазе, "");
	СтрокаПутиКИнформационнойБазе = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(СтрЗаменить(СтрокаПутиКИнформационнойБазе, """", "")) + "1Cv8.1CD";
	
	АдресЭлектроннойПочты = ?(Параметры.РежимОбновления = 2 И Параметры.ВыслатьОтчетНаПочту, Параметры.АдресЭлектроннойПочты, "");
	
	// Используется КаталогВременныхФайлов вместо ПолучитьИмяВременногоФайла, так как каталог не должен удаляться 
	// автоматически при завершении клиентского приложения.
	// В него сохраняются исполняемые файлы, лог выполнения и резервная копия (при определенной настройке).
	КаталогВременныхФайловОбновления = КаталогВременныхФайлов() + "1Cv8Update." + Формат(ОбщегоНазначенияКлиент.ДатаСеанса(), "ДФ=ггММддЧЧммсс") + "\";
	
	Если Параметры.СоздаватьРезервнуюКопию = 1 Тогда 
		КаталогРезервнойКопии = КаталогВременныхФайловОбновления;
	ИначеЕсли Параметры.СоздаватьРезервнуюКопию = 2 Тогда 
		КаталогРезервнойКопии = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(Параметры.ИмяКаталогаРезервнойКопииИБ);
	Иначе 
		КаталогРезервнойКопии = "";
	КонецЕсли;
	
	СоздаватьРезервнуюКопию = ЭтоФайловаяБаза И (Параметры.СоздаватьРезервнуюКопию = 1 Или Параметры.СоздаватьРезервнуюКопию = 2);
	
	ВыполнитьОтложенныеОбработчики = Ложь;
	ЭтоОтложенноеОбновление = (Параметры.РежимОбновления = 2);
	ТекстыМакетов = ОбновлениеКонфигурацииВызовСервера.ТекстыМакетов(ПараметрыПриложения["СтандартныеПодсистемы.СообщенияДляЖурналаРегистрации"], 
		ИнтерактивныйРежим, ВыполнитьОтложенныеОбработчики, ЭтоОтложенноеОбновление);
	ИмяПользователя = ПараметрыАдминистрирования.ИмяАдминистратораИнформационнойБазы;
	
	Если ЭтоОтложенноеОбновление Тогда 
		ГенераторСлучайныхЧисел = Новый ГенераторСлучайныхЧисел;
		КодЗадачи = Формат(ГенераторСлучайныхЧисел.СлучайноеЧисло(1000, 9999), "ЧГ=0");
		ИмяЗадачи = ИмяЗадачиScheduleService(КодЗадачи);
	КонецЕсли;
	
	ПараметрыЗапускаПредприятия = ОбщегоНазначенияСлужебныйКлиент.ПараметрыЗапускаПредприятияИзСкрипта();
	
	ВыполнитьОбновлениеКонфигурации = Параметры.Свойство("КонфигурацияИзменена") И Параметры.КонфигурацияИзменена;
	ВыполнитьЗагрузкуРасширений = Параметры.Свойство("ЗагрузитьРасширения") И Параметры.ЗагрузитьРасширения;
	
	ОбластьПараметров = ТекстыМакетов.ОбластьПараметров;
	ВставитьПараметрСкрипта("ИмяИсполняемогоФайлаКонфигуратора" , ИмяИсполняемогоФайлаКонфигуратора          , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("ИмяИсполняемогоФайлаКлиента"       , ИмяИсполняемогоФайлаКлиента                , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("ПутьКCOMСоединителю"               , ПутьКCOMСоединителю                        , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("КодировкаЛогФайла"               	, КодировкаЛогФайла                       	 , Ложь, ОбластьПараметров);
	ВставитьПараметрСкрипта("ПараметрПутиКИнформационнойБазе"   , ПараметрПутиКИнформационнойБазе            , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("СтрокаПутиКФайлуИнформационнойБазы", СтрокаПутиКИнформационнойБазе              , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("СтрокаСоединенияИнформационнойБазы", СтрокаСоединенияИнформационнойБазы         , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("СобытиеЖурналаРегистрации"         , СобытиеЖурналаРегистрации()                , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("АдресЭлектроннойПочты"             , АдресЭлектроннойПочты                      , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("ИмяАдминистратораОбновления"       , ИмяПользователя                            , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("ИмяCOMСоединителя"                 , ИмяCOMСоединителя                          , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("КаталогРезервнойКопии"             , КаталогРезервнойКопии                      , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("СоздаватьРезервнуюКопию"           , СоздаватьРезервнуюКопию                    , Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("ВосстанавливатьИнформационнуюБазу" , Параметры.ВосстанавливатьИнформационнуюБазу, Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("БлокироватьСоединенияИБ"           , Не ЭтоФайловаяБаза                         , Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("ИспользоватьCOMСоединитель"        , ИспользоватьCOMСоединитель                 , Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("ЗапускСеансаПослеОбновления"       , Не Параметры.ЗавершениеРаботыСистемы       , Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("ВыполнятьСжатиеТаблицИБ"           , ЭтоФайловаяБаза                            , Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("ВыполнитьОтложенныеОбработчики"    , ВыполнитьОтложенныеОбработчики             , Ложь  , ОбластьПараметров);
	ВставитьПараметрСкрипта("ИмяЗадачиПланировщикаЗадач"        , ИмяЗадачи                                  , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("ПараметрыЗапускаПредприятия"       , ПараметрыЗапускаПредприятия                , Истина, ОбластьПараметров);
	ВставитьПараметрСкрипта("КодРазблокировки"       			, "ПакетноеОбновлениеКонфигурацииИБ"         , Ложь,   ОбластьПараметров);
	ВставитьПараметрСкрипта("ВыполнитьОбновлениеКонфигурации"  	, ВыполнитьОбновлениеКонфигурации			 , Ложь,   ОбластьПараметров);
	ВставитьПараметрСкрипта("ВыполнитьЗагрузкуРасширений"       , ВыполнитьЗагрузкуРасширений				 , Ложь,   ОбластьПараметров);
	
	СоздатьКаталог(КаталогВременныхФайловОбновления);
	ИнформацияОбИсправлениях = ИнформацияОбИсправлениях(Параметры, КаталогВременныхФайловОбновления);
	ОбластьПараметров = СтрЗаменить(ОбластьПараметров, "[ИменаФайловОбновления]", ИменаФайловОбновления(Параметры));
	ОбластьПараметров = СтрЗаменить(ОбластьПараметров, "[ИменаФайловИсправлений]", ИнформацияОбИсправлениях.Установить);
	ОбластьПараметров = СтрЗаменить(ОбластьПараметров, "[ИменаУдаляемыхИсправлений]", ИнформацияОбИсправлениях.Удалить);
	
	ТекстыМакетов.МакетФайлаОбновленияКонфигурации = ОбластьПараметров + ТекстыМакетов.МакетФайлаОбновленияКонфигурации;
	ТекстыМакетов.Удалить("ОбластьПараметров");
	
	//
	ЗаписатьТекстВФайл(КаталогВременныхФайловОбновления + "main.js", ТекстыМакетов.МакетФайлаОбновленияКонфигурации);
	
	// Вспомогательный файл: helpers.js.
	ЗаписатьТекстВФайл(КаталогВременныхФайловОбновления + "helpers.js", ТекстыМакетов.ДопФайлОбновленияКонфигурации);
	
	Если ИнтерактивныйРежим Тогда
		БиблиотекаКартинок.ЗаставкаВнешнейОперации.Записать(КаталогВременныхФайловОбновления + "splash.png");
		БиблиотекаКартинок.ЗначокЗаставкиВнешнейОперации.Записать(КаталогВременныхФайловОбновления + "splash.ico");
		БиблиотекаКартинок.ДлительнаяОперация48.Записать(КаталогВременныхФайловОбновления + "progress.gif");

		ИмяГлавногоФайлаСкрипта = КаталогВременныхФайловОбновления + "splash.hta";
		ЗаписатьТекстВФайл(ИмяГлавногоФайлаСкрипта, ТекстыМакетов.ЗаставкаОбновленияКонфигурации);
	Иначе
		ИмяГлавногоФайлаСкрипта = КаталогВременныхФайловОбновления + "updater.js";
		ЗаписатьТекстВФайл(ИмяГлавногоФайлаСкрипта, ТекстыМакетов.НеинтерактивноеОбновлениеКонфигурации);
	КонецЕсли;
	
	Если ЭтоОтложенноеОбновление Тогда 
		
		ДатаЗапуска = Формат(Параметры.ДатаВремяОбновления, "ДФ=yyyy-MM-ddTHH:mm:ss");
		
		ПутьСкрипта = СтандартныеПодсистемыКлиент.КаталогСистемныхПриложений() + "wscript.exe";
		ПараметрыСкрипта = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("//nologo ""%1"" /p1:""%2"" /p2:""%3""",
			ИмяГлавногоФайлаСкрипта,
			СтрокаUnicode(ПараметрыАдминистрирования.ПарольАдминистратораИнформационнойБазы),
			СтрокаUnicode(ПараметрыАдминистрирования.ПарольАдминистратораКластера));
		
		ОписаниеЗадачи = НСтр("ru = 'Обновление конфигурации 1С:Предприятие'");
		
		СкриптСозданияЗадачиПланировщикаЗадач = ТекстыМакетов.СкриптСозданияЗадачиПланировщикаЗадач;
		
		ВставитьПараметрСкрипта("ДатаЗапуска" , ДатаЗапуска, Истина, СкриптСозданияЗадачиПланировщикаЗадач);
		ВставитьПараметрСкрипта("ПутьСкрипта" , ПутьСкрипта, Истина, СкриптСозданияЗадачиПланировщикаЗадач);
		ВставитьПараметрСкрипта("ПараметрыСкрипта" , ПараметрыСкрипта, Истина, СкриптСозданияЗадачиПланировщикаЗадач);
		ВставитьПараметрСкрипта("ИмяЗадачи" , ИмяЗадачи, Истина, СкриптСозданияЗадачиПланировщикаЗадач);
		ВставитьПараметрСкрипта("ОписаниеЗадачи" , ОписаниеЗадачи, Истина, СкриптСозданияЗадачиПланировщикаЗадач);
		
		ИмяСкриптаСозданияЗадачиПланировщикаЗадач = КаталогВременныхФайловОбновления + "addsheduletask.js";
		ЗаписатьТекстВФайл(ИмяСкриптаСозданияЗадачиПланировщикаЗадач, СкриптСозданияЗадачиПланировщикаЗадач);
		
		Параметры.КодЗадачиПланировщика = КодЗадачи;
		
		Параметры.Вставить("ИмяСкриптаСозданияЗадачиПланировщикаЗадач", ИмяСкриптаСозданияЗадачиПланировщикаЗадач);
		
	КонецЕсли;
	
	ЗаписатьТекстВФайл(КаталогВременныхФайловОбновления + "templog.txt",
		СтандартныеПодсистемыКлиент.ИнформацияДляПоддержки(), КодировкаТекста.Системная);
	
	ЗаписатьТекстВФайл(КаталогВременныхФайловОбновления + "add-delete-patches.js",
		ТекстыМакетов.СкриптУдаленияПатчей);
	
	Возврат ИмяГлавногоФайлаСкрипта;
	
КонецФункции

Процедура ЗаписатьТекстВФайл(ПолноеИмяФайла, Текст, Кодировка = Неопределено)
	
	Если Кодировка = Неопределено Тогда
		Кодировка = КодировкаФайловПрограммыОбновления();
	КонецЕсли;
	
	ФайлСкрипта = Новый ЗаписьТекста(ПолноеИмяФайла, Кодировка);
	ФайлСкрипта.Записать(Текст);
	ФайлСкрипта.Закрыть();
	
КонецПроцедуры

// Параметры:
//  Параметры - см. УстановитьОбновление.Параметры
//  ПараметрыАдминистрирования - см. СтандартныеПодсистемыСервер.ПараметрыАдминистрирования.
//
Процедура ЗапуститьСкриптОбновления(Параметры, ПараметрыАдминистрирования)
	
	Контекст = Новый Структура;
	Контекст.Вставить("Параметры", Параметры);
	Контекст.Вставить("ПараметрыАдминистрирования", ПараметрыАдминистрирования);
	
	ПараметрыФормы = Новый Структура("ИмяПервогоФайлаОбновления",
		ИменаФайловОбновления(Параметры, Истина));
	
	Оповещение = Новый ОписаниеОповещения("ЗапуститьСкриптОбновленияПослеПроверкиФайлаОбновления",
		ЭтотОбъект, Контекст);
	
	Форма = ОткрытьФорму("ОбщаяФорма.ПроверкаФайлаОбновления", ПараметрыФормы,,,,,
		Оповещение, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
	
	Если Форма = Неопределено Тогда
		ЗапуститьСкриптОбновленияПриОчисткеДанных(Контекст);
	ИначеЕсли Не Форма.Открыта() Тогда
		ЗапуститьСкриптОбновленияПослеПроверкиФайлаОбновления(Форма.Результат, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//  Контекст - Структура:
//   * Параметры - см. УстановитьОбновление.Параметры
//   * ПараметрыАдминистрирования - см. СтандартныеПодсистемыСервер.ПараметрыАдминистрирования.
//  Результат - Булево, Неопределено
//
Процедура ЗапуститьСкриптОбновленияПослеПроверкиФайлаОбновления(Результат, Контекст) Экспорт
	
	Если Результат = Истина Тогда
		ЗапуститьСкриптОбновленияПослеОчисткиУстаревшихДанных(Истина, Контекст);
	Иначе
		ЗапуститьСкриптОбновленияПриОчисткеДанных(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//  Контекст - см. ЗапуститьСкриптОбновленияПослеПроверкиФайлаОбновления.Контекст
//
Процедура ЗапуститьСкриптОбновленияПриОчисткеДанных(Контекст)
	
	ПолноеИмяФормы = "Обработка.РезультатыОбновленияПрограммы.Форма.ОчисткаУстаревшихДанных";
	
	Окна = ПолучитьОкна();
	Для Каждого Окно Из Окна Цикл
		Для Каждого Форма Из Окно.Содержимое Цикл
			Если Форма.ИмяФормы = ПолноеИмяФормы И Форма.Открыта() Тогда
				Форма.Закрыть();
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Оповещение = Новый ОписаниеОповещения("ЗапуститьСкриптОбновленияПослеОчисткиУстаревшихДанных",
		ЭтотОбъект, Контекст);
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ОчиститьИЗакрыть", Истина);
	
	ОткрытьФорму(ПолноеИмяФормы, ПараметрыФормы,,,,,
		Оповещение, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
	
КонецПроцедуры

// Параметры:
//  Результат - Булево, Неопределено
//  Контекст - см. ЗапуститьСкриптОбновленияПослеПроверкиФайлаОбновления.Контекст
//
Процедура ЗапуститьСкриптОбновленияПослеОчисткиУстаревшихДанных(Результат, Контекст) Экспорт
	
	Если Результат <> Истина Тогда
		Если Результат <> Ложь Тогда
			ПоказатьПредупреждение(, НСтр("ru = 'Обновление конфигурации отменено.'"));
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	ЗапуститьСкриптОбновленияЗавершение(Контекст.Параметры, Контекст.ПараметрыАдминистрирования);
	
КонецПроцедуры

// Параметры:
//  Параметры - см. УстановитьОбновление.Параметры
//  ПараметрыАдминистрирования - см. СтандартныеПодсистемыСервер.ПараметрыАдминистрирования.
//
Процедура ЗапуститьСкриптОбновленияЗавершение(Параметры, ПараметрыАдминистрирования)
	
	ИмяГлавногоФайлаСкрипта = СформироватьФайлыСкриптаОбновления(Истина, Параметры, ПараметрыАдминистрирования);
	ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(), "Информация",
		НСтр("ru = 'Выполняется процедура обновления конфигурации:'") + " " + ИмяГлавногоФайлаСкрипта);
	ОбновлениеКонфигурацииВызовСервера.ЗаписатьСтатусОбновления(ИмяПользователя(), Истина, Ложь, Ложь,
		ИмяГлавногоФайлаСкрипта, ПараметрыПриложения["СтандартныеПодсистемы.СообщенияДляЖурналаРегистрации"]);
		
	НеОстанавливатьВыполнениеСценариев();
	
	ПутьКПрограммеЗапуска = СтандартныеПодсистемыКлиент.КаталогСистемныхПриложений() + "mshta.exe";
	
	СтрокаЗапуска = """%1"" ""%2"" [p1]%3[/p1][p2]%4[/p2]";
	СтрокаЗапуска = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаЗапуска,
		ПутьКПрограммеЗапуска, ИмяГлавногоФайлаСкрипта,
		СтрокаUnicode(ПараметрыАдминистрирования.ПарольАдминистратораИнформационнойБазы),
		СтрокаUnicode(ПараметрыАдминистрирования.ПарольАдминистратораКластера));
	
	Если СтандартныеПодсистемыКлиент.ЭтоБазоваяВерсияКонфигурации() Тогда
		ОбновлениеКонфигурацииВызовСервера.УдалитьИсправленияИзСкрипта();
	КонецЕсли;
	КодВозврата = Неопределено;
	ЗапуститьПриложение(СтрокаЗапуска,,, КодВозврата); // АПК:534 запуск скрипта обновления.
	ПараметрыПриложения.Вставить("СтандартныеПодсистемы.ПропуститьПредупреждениеПередЗавершениемРаботыСистемы", Истина);
	ЗавершитьРаботуСистемы(Ложь);
	
КонецПроцедуры

Процедура НеОстанавливатьВыполнениеСценариев()
	
	Оболочка = Новый COMОбъект("Wscript.Shell");
	Оболочка.RegWrite("HKCU\Software\Microsoft\Internet Explorer\Styles\MaxScriptStatements", 1107296255, "REG_DWORD");

КонецПроцедуры

Процедура ЗапланироватьОбновлениеКонфигурации(Параметры, ПараметрыАдминистрирования)
	
	СформироватьФайлыСкриптаОбновления(Ложь, Параметры, ПараметрыАдминистрирования);
	
	ПараметрыЗапускаПрограммы = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
	ПараметрыЗапускаПрограммы.ВыполнитьСНаивысшимиПравами = Истина;
	
	КомандаЗапуска = Новый Массив;
	КомандаЗапуска.Добавить("wscript.exe");
	КомандаЗапуска.Добавить("//nologo");
	КомандаЗапуска.Добавить(Параметры.ИмяСкриптаСозданияЗадачиПланировщикаЗадач);
	
	ФайловаяСистемаКлиент.ЗапуститьПрограмму(КомандаЗапуска, ПараметрыЗапускаПрограммы);
	
	ОбновлениеКонфигурацииВызовСервера.ЗаписатьСтатусОбновления(ИмяПользователя(), Истина, Ложь, Ложь);
	
КонецПроцедуры

#КонецЕсли

// Возвращает Истина, если конфигуратор доступен.
//
// См. ОбщегоНазначения.РежимОтладки
//
// Возвращаемое значение:
//  Булево - Истина, если конфигуратор доступен.
//
Функция ПоддерживаетсяПакетныйРежимКонфигуратора()
	
#Если ВебКлиент Или МобильныйКлиент Тогда
	Возврат Ложь;
#Иначе
	Конфигуратор = КаталогПрограммы() + СтандартныеПодсистемыКлиент.ИмяИсполняемогоФайлаПриложения(Истина);
	ФайлКонфигуратора = Новый Файл(Конфигуратор);
	Возврат ФайлКонфигуратора.Существует(); // АПК:566 синхронные вызовы вне веб-клиента разрешены;
#КонецЕсли
	
КонецФункции

#КонецОбласти